#!BPY

""" Registration info for Blender menus:
Name: 'XNA Exporter (.x)...'
Blender: 242
Group: 'Export'
Tip: 'Export to DirectX and XNA XML file format format.'
"""
__author__ = "Frederic Souchu, based on Arben (Ben) Omari work"
__url__ = ("blender", "elysiun", "Author's site, http://www.omariben.too.it")
__version__ = "1.2"

__bpydoc__ = """\
This script exports a Blender mesh with armature to DirectX 8's text file
format.
The script also exports a .x-info XML file with additional information to be processed by a custom XNA processor.
Additional a .x-scene-info XML can be generated with scene information (lights, camera...)

"""
# DirectXExporter.py version 4.0

import Blender
from Blender import Types,Object,NMesh,Material,Armature,Mesh,Lamp,Camera,Constraint,Group
from Blender.Mathutils import *
from Blender import Draw, BGL
from Blender.BGL import *
import math
# for property group management
from Blender.Types import IDGroupType, IDArrayType

global mat_flip,index_list,space,bone_list,mat_dict
global anim,flip_norm,ticks,hard_norm,recalc_norm,Bl_norm,export_scene
bone_list =[]
index_list = []
mat_dict = {}
space = 0;anim=0;flip_norm=0;ticks= 25
Bl_norm = 0;recalc_norm = 0;hard_norm = 1
export_scene = 0

toggle_val = 0
toggle1_val = 0
toggle2_val = 0
toggle3_val = 0
toggle4_val = 0
toggle5_val = Bl_norm
toggle6_val = recalc_norm
toggle7_val = hard_norm
anim_tick = Draw.Create(25)


#***********************************************
# MAIN
#***********************************************

def my_callback(filename):
	if filename.find('.x', -2) <= 0: filename += '.x' 
	xexport = xExport(filename)
	xexport.exportAllObjs()

def my_callback_sel(filename):
	if filename.find('.x', -2) <= 0: filename += '.x' 
	xexport = xExport(filename)
	xexport.exportSelMesh()
def event(evt, val):	
		if evt == Draw.ESCKEY:
			Draw.Exit()                
			return

def button_event(evt): 
  	global toggle_val,toggle1_val,toggle2_val,toggle3_val,toggle4_val,toggle5_val,toggle6_val,toggle7_val
	global flip_norm,anim,ticks,hard_norm,Bl_norm,recalc_norm,export_scene
	arg = __script__['arg']
  	if evt == 1:
		toggle_val = 1 - toggle_val
		anim = toggle_val
		Draw.Redraw(1)
	if evt == 2:
		toggle1_val = 1 - toggle1_val
		flip_norm = toggle1_val
		Draw.Redraw(1)
	if evt == 3:
		toggle3_val = 1 - toggle3_val
		export_scene = toggle3_val
		Draw.Redraw(1)
	if evt == 10:
		toggle5_val = 1 - toggle5_val
		if toggle5_val==1:
			toggle6_val = 0
			toggle7_val = 0
		else :
			toggle6_val = 1
			toggle7_val = 1
		hard_norm = toggle7_val
		recalc_norm = toggle6_val
		Bl_norm = toggle5_val
		Draw.Redraw(1)
	if evt == 11:
		toggle6_val = 1 - toggle6_val
		if toggle6_val==1:
			toggle5_val = 0
			toggle7_val = 0
		else :
			toggle5_val = 1
			toggle7_val = 1
		hard_norm = toggle7_val
		recalc_norm = toggle6_val
		Bl_norm = toggle5_val
		Draw.Redraw(1)
	if evt == 12:
		toggle7_val = 1 - toggle7_val
		if toggle7_val==1:
			toggle6_val = 0
			toggle5_val = 0
		else :
			toggle6_val = 1
			toggle5_val = 1
		hard_norm = toggle7_val
		recalc_norm = toggle6_val
		Bl_norm = toggle5_val
		Draw.Redraw(1)
	if evt == 6:
		ticks = anim_tick.val
	if evt == 7:
		fname = Blender.sys.makename(ext = ".x")
		Blender.Window.FileSelector(my_callback, "Export DirectX", fname)
	if evt == 8:
		fname = Blender.sys.makename(ext = ".x")
		Blender.Window.FileSelector(my_callback_sel, "Export DirectX", fname)
	if evt == 9:
		Draw.Exit()
		
	
def draw():
		global animsg,flipmsg,swapmsg,anim_tick
		global flip_norm,anim,ticks,recalc_norm,Bl_norm,hard_norm,export_scene
		glClearColor(0.55,0.6,0.6,1)
		glClear(BGL.GL_COLOR_BUFFER_BIT)
		#external box
		glColor3f(0.2,0.3,0.3)
		rect(10,402,300,382)
		#--
		#glColor3f(0.3,0.4,0.4)
		#rect(11,399,298,398)
		#--
		glColor3f(0.5,0.75,0.65)
		rect(14,398,292,30)
		#--
		glColor3f(0.5,0.75,0.65)
		rect(14,366,292,160)
		#--
		glColor3f(0.5,0.75,0.65)
		rect(14,202,292,60)
		#--
		glColor3f(0.5,0.75,0.65)
		rect(14,138,292,40)
		#--
		glColor3f(0.5,0.75,0.65)
		rect(14,94,292,70)
		
		glColor3f(0.8,.8,0.6)
		glRasterPos2i(20, 380)
		Draw.Text("XNA Exporter ",'large')
		Draw.Text("(for Blender 2.44)", 'small')
		#-------Aniamtion toggle---------------------------------------------
		Draw.Toggle("Anim", 1, 20, 330, 55, 20, toggle_val,"export animations")
		if toggle_val :
			anim = 1
			animsg = "animation will be exported"
		else:
			anim = 0
			animsg = "animation will be not exported"
		glRasterPos2i(100,335)
		Draw.Text(animsg)
		#---Flip normals toggle-----------------------------------------------
		Draw.Toggle("Flip norm", 2, 20, 300, 55, 20, toggle1_val,"invert normals")
		if toggle1_val :
			flip_norm = 1
			flipmsg = "flipped normals"
		else:
			flip_norm = 0
			flipmsg = "not flipped normals"
		glRasterPos2i(100,305)
		Draw.Text(flipmsg)
		#------Export as scene toggle----------------------------------------------------------------
		Draw.Toggle("Scene", 3, 20, 245, 55, 20, toggle3_val,"export as a scene")
		if toggle3_val :
			export_scene = 1
			swapmsg = "Scene"
		else:
			export_scene = 0
			swapmsg = "Object(s)"
		glRasterPos2i(100,245)
		Draw.Text(swapmsg)
		#------Blender Normals toggle----------------------------------------------------------------
		Draw.Toggle("Bl.normals", 10, 20, 105, 75, 25, toggle5_val,"export normals as in Blender")
		if toggle5_val :
			Bl_norm = 1
		#------Recalculate Normals toggle----------------------------------------------------------------
		Draw.Toggle("recalc.no", 11, 120, 105, 75, 25, toggle6_val,"export recalculated normals")
		if toggle6_val :
			recalc_norm = 1
		#------Recalculate Normals toggle----------------------------------------------------------------
		Draw.Toggle("no smooth", 12, 220, 105, 75, 25, toggle7_val,"every vertex has the face normal,no smoothing")
		if toggle7_val :
			hard_norm = 1
		#------Draw Button export----------------------------------------------------------------
		exp_butt = Draw.Button("Export All",7,20, 155, 75, 30, "export all the scene objects")
		sel_butt = Draw.Button("Export Sel",8,120, 155, 75, 30, "export the selected object")
		exit_butt = Draw.Button("Exit",9,220, 155, 75, 30, "exit")
		glRasterPos2i(20,75)
		Draw.Text("Based on Arben OMARI work")
			
def rect(x,y,width,height):
		glBegin(GL_LINE_LOOP)
		glVertex2i(x,y)
		glVertex2i(x+width,y)
		glVertex2i(x+width,y-height)
		glVertex2i(x,y-height)
		glEnd()
		
def rectFill(x,y,width,height):
		glBegin(GL_POLYGON)
		glVertex2i(x,y)
		glVertex2i(x+width,y)
		glVertex2i(x+width,y-height)
		glVertex2i(x,y-height)
		glEnd()
		
		
		
Draw.Register(draw, event, button_event)


		

#***********************************************
#***********************************************
#                EXPORTER
#***********************************************
#***********************************************

class xExport:
	def __init__(self, filename):
		self.file = open(filename, "w")
		# additional XML file for object extended information (hull...)
		if export_scene == 1:
			self.xml_file = open(filename + "-scene-info","w")
		else:
			self.xml_file = open(filename + "-info","w")

	#***********************************************
	#Select Scene objects
	#***********************************************
	# Returns only top level objects (e.g. with no parents)
	#***********************************************
	def getSceneObjects(self):
			parent_list = []
			scene = Blender.Scene.GetCurrent()
			for obj in scene.objects:
				# in a visible layer?
				if obj.Layers & scene.Layers:
					# support object types
					if obj.type in ('Mesh', 'Armature', 'Empty'):
						# top level object?
						if obj.parent == None :
							parent_list.append(obj)
			return parent_list
	
	#***********************************************
	#Selected objects
	#***********************************************
	def getSelectedObjects(self):
			parent_list = []
			selected_list = Object.GetSelected()
			for obj in selected_list:
				if obj.type in ('Mesh', 'Armature', 'Empty'):
					#Pick only top level objects or objects with no selected parents
					if obj.parent == None or obj.parent not in selected_list:
						parent_list.append(obj)
			return parent_list
	
	def getChildren(self,parentObj):
		child_list = []
		for obj in Blender.Scene.GetCurrent().objects:
			if obj.parent == parentObj:
				child_list.append(obj)
		return child_list

	def getLocMat(self, obj):
		return obj.matrixLocal
	
	#***********************************************
	# Convert the Blender name into a DirectX compatible name.
	#***********************************************
	def getNormalizedName(self, name):
		return name.replace(".","").replace(" ","")
	
	def writeObjFrames(self,obj,ishull,isgeometry):
		global space,chld_obj,ch_list
		if isgeometry == 1:
			print "Writing game geometry: ", obj.name
			# write geometry data points
			self.writeGeometry(obj)			
		elif ishull == 1:
			print "Writing hull: ", obj.name
			mat = self.getLocMat(obj)
			mat_c = Matrix(mat)
			name = obj.name
			name_f = self.getNormalizedName(name)
			# export hull 'bone'
			self.writeArmFrames(mat_c, name_f)
			# write hull data points
			self.writeHull(obj, name_f)
		elif obj.type == "Empty":
			print "Writing empty: ", obj.name
			mat = self.getLocMat(obj)
			mat_c = Matrix(mat)
			name = obj.name
			name_f = self.getNormalizedName(name)
			self.writeArmFrames(mat_c, name_f)
			self.writeProperties(obj)
		elif obj.type == "Mesh":
			print "Writing mesh: ", obj.name
			self.exportMesh(obj)
			
	def writeObjects(self,obj):
		global space,ch_list
		space += 1
		if obj :
			for ob in obj:
				if ob not in ch_list:
					is_hull = 0
					is_geometry = 0
					is_sceneItem = 0
					print "exporting: ", ob.name
					#xml+direct.x information
					#normalize the name
					norm_name = self.getNormalizedName(ob.name)
					if self.isGeometry(ob):
						is_geometry = 1
						# game geometry
						self.xml_file.write("<Geometry name=\"%s\">" % (norm_name))
					elif ob.type == "Empty":
						# new empty entry (e.g. a bone or empty axis)
						is_sceneItem = 1
						self.xml_file.write("<SceneItemInfo type=\"empty\" name=\"%sTransform\">" % (norm_name))
					elif ob.type == "Mesh":
						if self.isHull(ob):
							is_hull = 1
						else:
							# new mesh entry
							is_sceneItem = 1
							self.xml_file.write("<SceneItemInfo type=\"mesh\" name=\"%s\" renderIndex=\"%d\">" % (norm_name, ob.passIndex))
					# directX data (bone)
					self.writeObjFrames(ob,is_hull,is_geometry)
					ch_list.append(ob)
					ch_ob = self.getChildren(ob)
					self.writeObjects(ch_ob)
					if is_sceneItem == 1:
						#close scene information tag
						self.xml_file.write("</SceneItemInfo>")
					if is_geometry == 0:
						self.closeBrackets()
						self.file.write("// End of the Object %s \n" % (ob.name))
					else:
						self.xml_file.write("</Geometry>")

	def writeRootFrame(self):
		# identity matrix
		mat = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1])
		self.writeArmFrames(mat, "RootFrame")		
			
	##################################################################	
	
	#***********************************************
	#Export the scene
	#***********************************************
	def exportAllObjs(self):
		print "exporting scene..."
		obj = self.getSceneObjects()
		self.exportMeshes(obj)
		
	#***********************************************
	#Export the given objects
	#***********************************************		
	def exportMeshes(self,obj_list):
		global space,chld_obj,ch_list
		self.writeHeader()
		self.writeRootFrame()
		self.exportMaterials()
		# export scene mode?
		if export_scene == 1:
			self.exportScene()
		space += 1
		ch_list = []
		self.writeObjects(obj_list)
		self.file.write("}  // End of the Root Frame\n")		
		self.writeEnd()
	#######################################################
								
	#*********************************************** 
	# Export the material (shaders)
	#***********************************************
	def exportMaterials(self):
		materials = Material.Get()
		for mat in materials:
			if mat.users > 0:
				# xml information
				self.xml_file.write("<Material name=\"%s\">" % mat.name)
				# name of the shader
				material_shader = mat.properties['shader']
				if len(material_shader) > 0:
					self.xml_file.write("<Shader name=\"%s\"/>" % material_shader)			
				self.xml_file.write("<Color R=\"%f\" G=\"%f\" B=\"%f\" A=\"%f\"/>" % (mat.R, mat.G, mat.B, mat.alpha))
				self.xml_file.write("<Specular R=\"%f\" G=\"%f\" B=\"%f\"/>" % (mat.specR, mat.specG, mat.specB))
				self.xml_file.write("</Material>")			
			
	#***********************************************
	#Export Mesh without Armature
	#***********************************************
	def exportMesh(self, obj):
		global space
		space += 1
		tex = []
		# get meshes with all modifiers applied
		mesh = NMesh.GetRawFromObject(obj.name)
		#		
		self.writeTextures(obj, tex)		
		self.writeMeshcoordArm(obj, mesh, arm_ob = None)
		self.writeMeshMaterialList(obj, mesh, tex)		
		self.writeProperties(obj)
		self.writeMeshNormals(obj, mesh)
		self.writeMeshTextureCoords(obj, mesh)
		# fs - 15/04/2007 - using close bracket function
		self.closeBrackets();
		self.file.write("// End of the Mesh %s \n" % (obj.name))

	#***********************************************
	#Export the selected Mesh
	#***********************************************
	def exportSelMesh(self):
		print "exporting selected objects..."
		objs = self.getSelectedObjects()
		self.exportMeshes(objs)
		
	def closeBrackets(self):
		global space
		space = space-1
		tab = "  "
		self.file.write("%s" % (tab * space))
		self.file.write("}\n")

#*********************************************************************************************************************************************
	#***********************************************
	# Write Matrices
	#***********************************************
	def writeArmFrames(self, matx, name):
		global space
		tab = "  "
		self.file.write("%s" % (tab * space))
		#make sure frames/bones have a different name than meshes
		self.file.write("Frame %sTransform {\n\n" % (name))
		self.file.write("%s" % (tab * space))
		self.file.write("  FrameTransformMatrix {\n")
		self.writeFrame(matx)
	
	#***********************************************
	# Write Frames
	#***********************************************
	def writeOffsFrames(self, matx, name):
		space = 1
		self.writeFrame(matx)
	
	 #***********************************************
	# Write Frames
	#***********************************************
	def writeFrame(self, matx):
		tab = "  "
		self.file.write("%s" % (tab * space))
		self.file.write("    %f,%f,%f,%f,\n" %
							(round(matx[0][0],4),round(matx[0][1],4),round(matx[0][2],4),round(matx[0][3],4)))
		self.file.write("%s" % (tab * space))
		self.file.write("    %f,%f,%f,%f,\n" %
							(round(matx[1][0],4),round(matx[1][1],4),round(matx[1][2],4),round(matx[1][3],4)))
		self.file.write("%s" % (tab * space))	
		self.file.write("    %f,%f,%f,%f,\n" %
							(round(matx[2][0],4),round(matx[2][1],4),round(matx[2][2],4),round(matx[2][3],4)))
		self.file.write("%s" % (tab * space))
		self.file.write("    %f,%f,%f,%f;;\n" %
							(round(matx[3][0],4),round(matx[3][1],4),round(matx[3][2],4),round(matx[3][3],4)))
		self.file.write("%s" % (tab * space))
		self.file.write("  }\n")
#*********************************************************************************************************************************************
	
	#***********************************************
	#HEADER
	#***********************************************  
	def writeHeader(self):
		self.file.write("xof 0303txt 0032\n\n\n")
		self.file.write("template VertexDuplicationIndices { \n\
 <b8d65549-d7c9-4995-89cf-53a9a8b031e3>\n\
 DWORD nIndices;\n\
 DWORD nOriginalVertices;\n\
 array DWORD indices[nIndices];\n\
}\n\
template XSkinMeshHeader {\n\
 <3cf169ce-ff7c-44ab-93c0-f78f62d172e2>\n\
 WORD nMaxSkinWeightsPerVertex;\n\
 WORD nMaxSkinWeightsPerFace;\n\
 WORD nBones;\n\
}\n\
template SkinWeights {\n\
 <6f0d123b-bad2-4167-a0d0-80224f25fabb>\n\
 STRING transformNodeName;\n\
 DWORD nWeights;\n\
 array DWORD vertexIndices[nWeights];\n\
 array float weights[nWeights];\n\
 Matrix4x4 matrixOffset;\n\
}\n\n")
		# write XML file headers
		self.xml_file.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n")
		self.xml_file.write("<ModelInfo>")		
		
	#***********************************************
	#CLOSE FILE
	#***********************************************
	def writeEnd(self):
		self.file.close()
		# xml file closure
		self.xml_file.write("</ModelInfo>")
		self.xml_file.close()
		print "... finished"


	#***********************************************
	#EXPORT TEXTURES
	#***********************************************
	def writeTextures(self,name, tex):
		mesh = name.data
		for face in mesh.faces:
			if face.image and face.image.name not in tex:
				tex.append(face.image.name)

	#***********************************************
	#EXPORT MESH DATA with armature (if any)
	#***********************************************
	def writeMeshcoordArm(self, obj, mesh, arm_ob):
		global index_list
		#TransformMatrix
		mat = self.getLocMat(obj)
		#Normalize the name
		name_f = self.getNormalizedName(obj.name)
		self.writeArmFrames(mat, name_f)
		self.file.write("Mesh %s {\n" % (name_f))    
		numface=len(mesh.faces)
		#VERTICES NUMBER
		numvert = 0
		for face in mesh.faces:
			numvert = numvert + len(face.v)
		self.file.write("%d;\n" % (numvert))
		if numvert == 0:
			print "Mesh named",mesh.name,"has no vertices.Problems may occur using the .x file"
		#VERTICES COORDINATES
		counter = 0
		for face in mesh.faces:
			counter += 1
			for n in range(len(face.v)):
				index_list.append(face.v[n].index)
				vec_vert = Vector([(face.v[n].co[0]), face.v[n].co[1], face.v[n].co[2], 1])
				if arm_ob :
					f_vec_vert = vec_vert * mat
				else :
					f_vec_vert = vec_vert
				self.file.write("%f; %f; %f;" % (round(f_vec_vert[0],4), round(f_vec_vert[1],4), round(f_vec_vert[2],4)))
				if counter == numface :
					if n == len(face.v)-1 :
						self.file.write(";\n")
					else :
						self.file.write(",\n")
				else :
					self.file.write(",\n")
			a3 = 0;b3 = 1;c3 = 2
			a4 = 0;b4 = 1;c4 = 2;d4 = 3

		#FACES NUMBER 
		self.file.write("%s;\n" % (numface))  
		coun,counter = 0, 0
		for face in mesh.faces :
			coun += 1
			if coun == numface:
				if len(face.v) == 3:
					self.file.write("3; %d, %d, %d;;\n" % (counter + a3, counter + b3, counter + c3))
					counter += 3
				elif len(face.v) == 4:
					self.file.write("4; %d, %d, %d, %d;;\n" % (counter + a4, counter + b4, counter + c4, counter + d4))
					counter += 4
				elif len(face.v) < 3:
					print "WARNING:the mesh has faces with less then 3 vertices"
					print "        It my be not exported correctly."
			else:
				
				if len(face.v) == 3:
					self.file.write("3; %d, %d, %d;,\n" % (counter + a3, counter + b3, counter + c3))
					counter += 3
				elif len(face.v) == 4:
					self.file.write("4; %d, %d, %d, %d;,\n" % (counter + a4, counter + b4, counter + c4, counter + d4))
					counter += 4
				elif len(face.v) < 3:
					print "WARNING:the mesh has faces with less then 3 vertices"
					print "        It my be not exported correctly."

	
	#***********************************************
	#MESH MATERIAL LIST (reference to the main Material list)
	#***********************************************
	def writeMeshMaterialList(self, obj, mesh, tex):		
		for mat in mesh.getMaterials():
			self.xml_file.write("<MaterialRef name=\"%s\"/>" % mat.name)

	#***********************************************
	#MESH NORMALS
	#***********************************************
	def writeMeshNormals(self,name,mesh):
		global flip_norm,hard_norm,recalc_norm,Bl_norm
		
		self.file.write("  MeshNormals {\n")
		#VERTICES NUMBER
		numvert = 0
		for face in mesh.faces:
			numvert = numvert + len(face.v)
		self.file.write("%d;\n" % (numvert))
		numfaces=len(mesh.faces)
		if flip_norm :
			fl = -1
		else :
			fl = 1
		#VERTICES NORMAL
		if Bl_norm:
			self.writeBlenderNormals(mesh,fl)
		if recalc_norm:
			self.writeRecalcNormals(mesh,fl)	
		if hard_norm:
			self.writeNoSmoothing(mesh,fl)
									
		a3 = 0;b3 = 1;c3 = 2
		a4 = 0;b4 = 1;c4 = 2;d4 = 3

		#FACES NUMBER 
		self.file.write("%s;\n" % (numfaces))  
		coun,counter = 0, 0
		for face in mesh.faces :
			coun += 1
			if coun == numfaces:
				if len(face.v) == 3:
					self.file.write("3; %d, %d, %d;;\n" % (counter + a3, counter + b3, counter + c3))
					counter += 3
				else :
					self.file.write("4; %d, %d, %d, %d;;\n" % (counter + a4, counter + b4, counter + c4, counter + d4))
					counter += 4
			else:
				
				if len(face.v) == 3:
					self.file.write("3; %d, %d, %d;,\n" % (counter + a3, counter + b3, counter + c3))
					counter += 3
				else :
					self.file.write("4; %d, %d, %d, %d;,\n" % (counter + a4, counter + b4, counter + c4, counter + d4))
					counter += 4
		self.file.write("}  //End of MeshNormals\n")
		
	def writeBlenderNormals(self,mesh,fl):
			numfaces=len(mesh.faces)
			#VERTICES NORMAL
			counter = 0
			for face in mesh.faces:
				counter += 1  
				for n in range(len(face.v)):
					self.file.write("    %f; %f; %f;" % (
									(round(face.v[n].no[0],6)*fl),(round(face.v[n].no[1],6)*fl),(round(face.v[n].no[2],6)*fl)))
					if counter == numfaces :
						if n == len(face.v)-1 :
							self.file.write(";\n")
						else :
							self.file.write(",\n")
					else :
						self.file.write(",\n")

	##############################################
	# Returns if given mesh is a hull		
	##############################################
	def isHull(self,obj):
		try:
			#get the hull flag from the game properties
			if obj.getProperty("hull"):
				return 1
		except:
			None
		return 0
		
	##############################################
	# Returns if given mesh is game geometry (exported as opage mesh)
	##############################################
	def isGeometry(self, obj):
		try:
			#get the hull flag from the game properties
			if obj.rbFlags & Blender.Object.RBFlags['GHOST']:
				return 1
		except:
			None
		return 0

	def writeGeometry(self,obj):
		mesh = obj.getData()
		# get matrix 
		mat = self.getLocMat(obj)
		#get vertices (special case for empty objects)
		if obj.type == "Empty":
			self.xml_file.write("<Vertex position=\"%f; %f; %f\"/>" % 
				((round(obj.loc[0],3)),
				 (round(obj.loc[1],3)),
				(round(obj.loc[2],3))))			
		else:
			print "Writing: faces(%s)" % (len(mesh.faces))
			for v in mesh.verts:
				vertex = mat * v.co
				self.xml_file.write("<Vertex position=\"%f; %f; %f\"/>" % 
					((round(vertex[0] + obj.loc[0],3)),
					 (round(vertex[1] + obj.loc[1],3)),
					(round(vertex[2] + obj.loc[2],3))))
		# write additional properties
		self.writeProperties(obj)

	def writeMeshGeometry(self,obj):
		self.xml_file.write("<Geometry>")
		mesh = obj.getData()
		#get vertices (special case for empty objects)
		if obj.type == "Empty":
			no = obj.matrixLocal[2]
			self.xml_file.write("<Vertex position=\"%f; %f; %f\" normal=\"%f; %f; %f\"/>" % 
				(round(obj.loc[0],3),
				 round(obj.loc[1],3),
				 round(obj.loc[2],3),
				 round(no[0],3),
				 round(no[1],3),
				 round(no[2],3)))			
		else:
			print "Writing: faces(%s)" % (len(mesh.faces))
			a3 = 0;b3 = 1;c3 = 2
			a4 = 0;b4 = 1;c4 = 2;d4 = 3
			counter = 0
			for face in mesh.faces :
				if len(face.v) == 3:
					self.xml_file.write("<Face vertices=\"%d; %d; %d\"/>" % (counter + a3, counter + b3, counter + c3))
					counter += 3
				else:
					self.xml_file.write("<Face vertices=\"%d; %d; %d; %d\"/>" % (counter + a4, counter + b4, counter + c4, counter + d4))
					counter += 4
			for v in mesh.verts:
				self.xml_file.write("<Vertex position=\"%f; %f; %f\" normal=\"%f; %f; %f\"/>" % 
					(round(v.co[0],3),
					 round(v.co[1],3),
					 round(v.co[2],3),
					 round(v.no[0],3),
					 round(v.no[1],3),
					 round(v.no[2],3)))
		self.xml_file.write("</Geometry>")
		
	def writeHull(self,obj,name):
		mesh = obj.getData()
		print "Writing: faces(%s)" % (len(mesh.faces))
		#link to parent transformation
		self.xml_file.write("<Hull name=\"%sTransform\">" % (name))
		#get hull vertices
		for v in mesh.verts:
			self.xml_file.write("<Vertex position=\"%f; %f; %f\"/>" % 
				((round(v.co[0],3)),
				 (round(v.co[1],3)),
				 (round(v.co[2],3))))
		#get hull faces
		for face in mesh.faces:
			print "Writing: face"
			#plane equation: all r (point in R3) such that normal.(r-point) = 0
			self.xml_file.write("<Plane normal=\"%f; %f; %f\" point=\"%f; %f; %f\"/>" % 
				((round(face.no[0],3)),
				 (round(face.no[1],3)),
				 (round(face.no[2],3)),
				 (round(face.v[0].co[0],3)),
				 (round(face.v[0].co[1],3)),
				 (round(face.v[0].co[2],3))))
		self.xml_file.write("</Hull>")

	def writeRecalcNormals(self,mesh,fl):
		numfaces=len(mesh.faces)
		normal_list = {}
		idx = 0
		for vertex in mesh.verts:
			v_norm = Vector([0, 0, 0])
			normal_list[idx] = v_norm
			idx += 1
			for face in mesh.faces:
				for verts in face.v:
					if verts.index == vertex.index :
							v_norm[0] += face.no[0]
							v_norm[1] += face.no[1]
							v_norm[2] += face.no[2]
			
			v_norm.normalize()
						
		counter = 0
		for face in mesh.faces:
				counter += 1 
				n = 0 
				for vert in face.v:
					n += 1
					norm = normal_list[vert.index]
					
					self.file.write("    %f; %f; %f;" % (
									(round(norm[0],6)*fl),(round(norm[1],6)*fl),(round(norm[2],6)*fl)))		
					if counter == numfaces :
						if n == len(face.v) :
							self.file.write(";\n")
						else :
							self.file.write(",\n")
					else :
						self.file.write(",\n")
						
	def writeNoSmoothing(self,mesh,fl):
		numfaces=len(mesh.faces)
		counter = 0
		for face in mesh.faces:
				counter += 1 
				n = 0 
				for n in range(len(face.v)):
					n += 1
					self.file.write("    %f; %f; %f;" % (
									(round(face.no[0],6)*fl),(round(face.no[1],6)*fl),(round(face.no[2],6)*fl)))
					
							
					if counter == numfaces :
						if n == len(face.v) :
							self.file.write(";\n")
						else :
							self.file.write(",\n")
					else :
						self.file.write(",\n")

	#***********************************************
	#MESH TEXTURE COORDS
	#***********************************************
	def writeMeshTextureCoords(self, name, mesh):
		if mesh.hasFaceUV():
			self.file.write("MeshTextureCoords {\n")
			#VERTICES NUMBER
			numvert = 0
			for face in mesh.faces:
				numvert += len(face.v)
			self.file.write("%d;\n" % (numvert))
			#UV COORDS
			numfaces = len(mesh.faces)
			counter = -1
			co = 0
			for face in mesh.faces:
				counter += 1
				co += 1
				for n in range(len(face.v)):
					self.file.write("%f;%f;" % (mesh.faces[counter].uv[n][0], -mesh.faces[counter].uv[n][1]))
					if co == numfaces :
						if n == len(face.v) - 1 :
							self.file.write(";\n")
						else :
							self.file.write(",\n")
					else :
						self.file.write(",\n")

			self.file.write("}  //End of MeshTextureCoords\n")

	#***********************************************
	#MESH/BONES PROPERTIES
	#***********************************************
	def writeProperties(self, obj):
		#ID properties
		for k, v in obj.properties.iteritems():
			self.xml_file.write("<Property name=\"%s\" value=\"%s\"/>" % (k, str(v)))
		#game properties (if any)
		export_mesh = 0
		for prop in obj.getAllProperties():
			if prop.name == "export_geom" and prop.data == 1:
				export_mesh = 1
			else:
				self.xml_file.write("<Property name=\"%s\" value=\"%s\"/>" % (prop.name, str(prop.data)))
		#actor properties
		if obj.rbFlags & Blender.Object.RBFlags['ACTOR']:
			self.xml_file.write("<Property name=\"actor\" value=\"1\"/>")			
		#export mesh?
		if export_mesh == 1:
			self.writeMeshGeometry(obj)

	#***********************************************
	#Export scene information:
	#Light(s)
	#Camera(s) 
	#***********************************************
	def exportScene(self):
		# TODO: optimize!!
		for obj in Object.Get():
			if obj.getType() == "Lamp":
				lamp = obj.getData()
				self.xml_file.write("<Light name=\"%s\" type=\"%s\" position=\"%f;%f;%f\" color=\"%f;%f;%f\" energy=\"%f\"/>" % (lamp.name,lamp.type,obj.loc[0],obj.loc[2],obj.loc[2],lamp.col[0],lamp.col[1],lamp.col[2],lamp.energy))
			if obj.getType() == "Camera":
				camera = obj.getData()
				self.xml_file.write("<Camera name=\"%s\" position=\"%f;%f;%f\" fov=\"%f\" clipStart=\"%f\" clipEnd=\"%f\">" % (camera.name,obj.loc[0],obj.loc[1],obj.loc[2],camera.angle,camera.clipStart,camera.clipEnd))
				# TODO: dump the camera transformation 
				# self.xml_file.write("<Transform row0="\"%f;%f;%f;%f\" row1="\"%f;%f;%f;%f\" row2="\"%f;%f;%f;%f\" row3="\"%f;%f;%f;%f\"/>" % (obj.mat[0][0],
				self.xml_file.write("</Camera>")
		for grp in Group.Get():
			if grp.users>0:
				print("group: %s") % (grp.name)
				self.xml_file.write("<Group name=\"" + self.getNormalizedName(grp.name) + "\">")
				for obGrp in grp.objects:
					print("group object: %s") % (obGrp.name)
					if obGrp.type == "Empty":
						self.xml_file.write("<SceneItemRef name=\"" + self.getNormalizedName(obGrp.name) + "Transform\"/>")
					else:
						self.xml_file.write("<SceneItemRef name=\"" + self.getNormalizedName(obGrp.name) + "\"/>")
				self.xml_file.write("</Group>")
